#include <thread>
#include <chrono>

#include "OperatingSystem.h"

namespace OS
{
#define SERIES_NAME "API without Secrets: Introduction to Vulkan"

	Window::Window() : parameters_()
	{

	}

	const WindowParameters Window::GetParameters() const
	{
		return parameters_;
	}


	LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
		switch (message) {
		case WM_SIZE:
		case WM_EXITSIZEMOVE:
			PostMessage(hWnd, WM_USER + 1, wParam, lParam);
			break;
		case WM_KEYDOWN:
		case WM_CLOSE:
			PostMessage(hWnd, WM_USER + 2, wParam, lParam);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		return 0;
	}

	Window::~Window() {
		if (parameters_.handle) {
			DestroyWindow(parameters_.handle);
		}

		if (parameters_.instance) {
			UnregisterClass(SERIES_NAME, parameters_.instance);
		}
	}

	bool Window::Create(const char *title) {
		parameters_.instance = GetModuleHandle(nullptr);

		// Register window class
		WNDCLASSEX wcex;

		wcex.cbSize = sizeof(WNDCLASSEX);

		wcex.style = CS_HREDRAW | CS_VREDRAW;
		wcex.lpfnWndProc = WndProc;
		wcex.cbClsExtra = 0;
		wcex.cbWndExtra = 0;
		wcex.hInstance = parameters_.instance;
		wcex.hIcon = NULL;
		wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
		wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
		wcex.lpszMenuName = NULL;
		wcex.lpszClassName = SERIES_NAME;
		wcex.hIconSm = NULL;

		if (!RegisterClassEx(&wcex)) {
			return false;
		}

		// Create window
		parameters_.handle = CreateWindow(SERIES_NAME, title, WS_OVERLAPPEDWINDOW, 20, 20, 500, 500, nullptr, nullptr, parameters_.instance, nullptr);
		if (!parameters_.handle) {
			return false;
		}

		return true;
	}

	bool Window::RenderingLoop(ProjectBase &project) const {
		// Display window
		ShowWindow(parameters_.handle, SW_SHOWNORMAL);
		UpdateWindow(parameters_.handle);

		// Main message loop
		MSG message;
		bool loop = true;
		bool resize = false;
		bool result = true;

		while (loop) {
			if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
				// Process events
				switch (message.message) {
					// Resize
				case WM_USER + 1:
					resize = true;
					break;
					// Close
				case WM_USER + 2:
					loop = false;
					break;
				}
				TranslateMessage(&message);
				DispatchMessage(&message);
			}
			else {
				// Resize
				if (resize) {
					resize = false;
					if (!project.OnWindowSizeChanged()) {
						result = false;
						break;
					}
				}
				// Draw
				if (project.ReadyToDraw()) {
					if (!project.Draw()) {
						result = false;
						break;
					}
				}
				else {
					std::this_thread::sleep_for(std::chrono::milliseconds(100));
				}
			}
		}

		return result;
	}
}